<?php
declare(strict_types=1);

namespace app\controller;

use support\Request;   
use support\Response;  
use support\Redis;    
use hg\apidoc\annotation as Apidoc;

/**
 * @Apidoc\Title("TCP 接入与入库指标统计")
 * @Apidoc\Group("http")
 * TCP 接入状态查询控制器
 *
 * 作用：
 * - 提供 GET /stats 接口，返回 TCP 客户端与入库消费相关的运行指标（来源于 Redis）
 * - 方便前端页面或验收脚本实时观测 TCP 登录、接收、队列与入库情况
 *
 * 示例访问：
 *   curl -s http://127.0.0.1:8787/tcp/stats
 */
class TcpStatsController
{
    /**
     * @Apidoc\Title("TCP 接入与入库指标")
     * @Apidoc\Method("GET")
     * @Apidoc\Url("/tcp/stats")
     * @Apidoc\Returned(name="target", type="string", desc="目标地址（例：tcp://gps.zhdkj.net:17910）")
     * @Apidoc\Returned(name="eol_primary", type="string", desc="登录首选行尾策略（NONE/CRLF/LF）")
     * @Apidoc\Returned(name="eol_order", type="string", desc="登录失败时轮换行尾顺序")
     * @Apidoc\Returned(name="send_delay_ms", type="int", desc="登录报文发送延时（毫秒）")
     * @Apidoc\Returned(name="login_status", type="string", desc="登录状态（sent/ok/failed/unknown）")
     * @Apidoc\Returned(name="last_login_at", type="int", desc="最近一次发送登录的时间戳")
     * @Apidoc\Returned(name="login_ok_at", type="int", desc="最近一次登录成功时间戳")
     * @Apidoc\Returned(name="last_connect", type="int", desc="最近一次连接建立时间戳")
     * @Apidoc\Returned(name="last_close", type="int", desc="最近一次连接关闭时间戳")
     * @Apidoc\Returned(name="last_error", type="string", desc="最近一次错误描述（含登录失败原因）")
     * @Apidoc\Returned(name="recv_packets", type="int", desc="解析入队包累计数")
     * @Apidoc\Returned(name="json_errors", type="int", desc="JSON解析失败累计数")
     * @Apidoc\Returned(name="last_packet_at", type="int", desc="最近一次接收到业务数据时间戳")
     * @Apidoc\Returned(name="saved_rows", type="int", desc="成功入库累计行数")
     * @Apidoc\Returned(name="last_saved_at", type="string", desc="最近一次写库时间（字符串）")
     * @Apidoc\Returned(name="queue_len", type="int", desc="待入库队列长度")
     * @Apidoc\Returned(name="bytes_in", type="int", desc="累计入站字节数")
     * @Apidoc\Returned(name="buffer_size", type="int", desc="当前缓冲区字节数")
     * @Apidoc\Returned(name="buffer_trunc", type="int", desc="缓冲截断次数")
     * @Apidoc\Returned(name="dropped", type="int", desc="背压丢弃条数")
     * @Apidoc\Returned(name="relogin_interval_sec", type="int", desc="重新登录间隔（秒）")
     * @Apidoc\Returned(name="last_relogin_at", type="int", desc="最近一次重新登录时间戳")
     * @Apidoc\Returned(name="relogin_count", type="int", desc="重新登录次数")
     * @Apidoc\Returned(name="samples", type="array", desc="队列数据样本（最多10条）")
     */
    public function stats(Request $request): Response
    {
        // 按字段逐一从 Redis 读取；使用 ?? 提供默认值，保证返回类型稳定
        // 接入与登录相关
        $loginOkAt   = (int)(Redis::get('gps:login_ok_at') ?? 0);       // 最近登录成功的时间戳
        $lastConnect = (int)(Redis::get('gps:last_connect_at') ?? 0);   // 最近连接建立时间
        $lastClose   = (int)(Redis::get('gps:last_close_at') ?? 0);     // 最近连接关闭时间
        $lastError   = (string)(Redis::get('gps:last_error') ?? '');    // 最近错误描述

        // 接收端（TCP 客户端）指标
        $recvPackets   = (int)(Redis::get('gps:recv_packets') ?? 0);    // 成功解析并入队的 JSON 包累计数
        $jsonErrors    = (int)(Redis::get('gps:json_errors') ?? 0);     // JSON 解析失败累计数
        $lastPacketAt  = (int)(Redis::get('gps:last_packet_at') ?? 0);  // 最近一次接收到业务数据的时间戳

        // 入库端（GpsSaver）指标
        $savedRows     = (int)(Redis::get('gps:saved_rows') ?? 0);      // 成功写入数据库的累计行数
        $lastSavedAt   = (string)(Redis::get('gps:last_saved_at') ?? ''); // 最近一次写库时间（字符串）

        // 队列长度（Redis 列表 gps:json）
        $queueLen      = (int)(Redis::lLen('gps:json') ?? 0);           // 当前待入库队列长度
        $data = [
            // 连接目标与登录参数（来自 GpsTcp 启动时写入）
            'target'         => (string)(Redis::get('gps:target') ?? ''),          // 目标地址（例：tcp://gps.zhdkj.net:17910）
            'eol_primary'    => (string)(Redis::get('gps:eol_primary') ?? ''),     // 登录首选行尾策略（NONE/CRLF/LF）
            'eol_order'      => (string)(Redis::get('gps:eol_order') ?? ''),       // 登录失败时轮换行尾顺序
            'send_delay_ms'  => (int)(Redis::get('gps:send_delay_ms') ?? 0),       // 登录报文发送延时（毫秒）

            // 登录动作状态（由 GpsTcp 在 onConnect/onMessage 写入）
            'login_status'   => (string)(Redis::get('gps:login_status') ?? ''),    // sent/ok/failed/unknown
            'last_login_at'  => (int)(Redis::get('gps:last_login_at') ?? 0),       // 最近一次发送登录的时间戳
            'login_ok_at'    => $loginOkAt,                                     // 最近一次登录成功时间戳

            // 连接与错误信息（由 GpsTcp 写入）
            'last_connect'   => $lastConnect,                                   // 最近一次连接建立时间戳
            'last_close'     => $lastClose,                                     // 最近一次连接关闭时间戳
            'last_error'     => $lastError,                                     // 最近一次错误描述（含登录失败原因）

            // 接收端数据统计（由 GpsTcp 写入）
            'recv_packets'   => $recvPackets,                                   // 成功解析并入队的 JSON 包累计数
            'json_errors'    => $jsonErrors,                                    // JSON 解析失败累计数
            'last_packet_at' => $lastPacketAt,                                  // 最近一次接收到业务数据时间戳

            // 入库端数据统计（由 GpsSaver 写入）
            'saved_rows'     => $savedRows,                                     // 成功写入数据库的累计行数
            'last_saved_at'  => $lastSavedAt,                                   // 最近一次写库时间（字符串）

            // 队列长度（Redis 列表 gps:json）
            'queue_len'      => $queueLen,                                      // 当前待入库队列长度

            // 扩展指标（可观测）
            'bytes_in'       => (int)(Redis::get('gps:bytes_in') ?? 0),       // 累计入站字节数
            'buffer_size'    => (int)(Redis::get('gps:buffer_size') ?? 0),    // 当前缓冲区字节数
            'buffer_trunc'   => (int)(Redis::get('gps:buffer_trunc') ?? 0),   // 缓冲截断次数
            'dropped'        => (int)(Redis::get('gps:dropped') ?? 0),        // 背压丢弃条数

            // 重新登录维持链接（厂家建议）
            'relogin_interval_sec' => (int)(Redis::get('gps:relogin_interval_sec') ?? 0),
            'last_relogin_at'      => (int)(Redis::get('gps:last_relogin_at') ?? 0),
            'relogin_count'        => (int)(Redis::get('gps:relogin_count') ?? 0),
        ];

        // 采样最近队列数据（最多 10 条，便于直观看到收到的数据情况）
        $samples = [];
        if ($queueLen > 0) {
            $samples = Redis::lRange('gps:json', 0, min(9, $queueLen - 1)) ?? [];
        }
        $data['samples'] = $samples;

        // 返回 JSON 响应（Webman helper：json() 自动设置 Content-Type 与序列化）
        return json($data);
    }
}